package com.ssy.lingxi.member.merchant.serviceimpl.base;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.Aes128Util;
import com.ssy.lingxi.common.utils.PasswordUtil;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.config.ServiceVariable;
import com.ssy.lingxi.member.merchant.entity.MemberDO;
import com.ssy.lingxi.member.merchant.entity.MemberUserDO;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberUserAuthTypeEnum;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.EmailVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.PayPasswordVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.PhoneVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.SmsCodeVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdateEmailVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdatePasswordVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdatePayPasswordVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdatePhoneVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.UserAccountSecurityQueryVO;
import com.ssy.lingxi.member.merchant.repository.MemberRepository;
import com.ssy.lingxi.member.merchant.repository.MemberUserRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseAccountSecurityService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.feign.ISmsFeignService;
import com.ssy.lingxi.member.merchant.utils.MailUtil;
import com.ssy.lingxi.member.merchant.utils.SecurityStringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;


/**
 * 用户账号安全接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-07-06
 */
@Service
public class BaseAccountSecurityServiceImpl implements IBaseAccountSecurityService {
    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private MemberRepository memberRepository;

    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private ISmsFeignService smsFeignService;

    /**
     * “账户安全”页面，查询用户的手机号码和邮箱，以掩码方式返回
     * @param userId 用户Id
     * @return 操作结果
     */
    @Override
    public Wrapper<UserAccountSecurityQueryVO> getPhoneAndEmail(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        UserAccountSecurityQueryVO queryVO = new UserAccountSecurityQueryVO();
        queryVO.setPhone(SecurityStringUtils.getMaskPhone(userDO.getCountryCode(), userDO.getPhone()));
        queryVO.setEmail(SecurityStringUtils.getMaskMail(userDO.getEmail()));
        queryVO.setHasPayPassword(StringUtils.hasLength(memberDO.getPayPassword()) ? EnableDisableStatus.ENABLE.getCode() : EnableDisableStatus.DISABLE.getCode());

        return Wrapper.success(queryVO);
    }

    /**
     * （通用）检查支付密码是否正确
     * @param memberId 会员Id
     * @param payPasswordVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkPayPassword(Long memberId, PayPasswordVO payPasswordVO) {
        MemberDO memberDO = memberRepository.findById(memberId).orElse(null);
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        if(!StringUtils.hasLength(memberDO.getPayPassword())) {
            return Wrapper.fail(ResponseCode.MC_MS_PAY_PASSWORD_NOT_SET);
        }

        String inputPayPassword;
        try {
            inputPayPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(payPasswordVO.getPayPassword()));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.SERVICE_ERROR);
        }

        if(!inputPayPassword.equals(memberDO.getPayPassword())) {
            return Wrapper.fail(ResponseCode.MC_MS_PAY_PASSWORD_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改登录密码（手机校验码验证）时，发送手机短信验证码
     * @param userId 用户Id
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePasswordSmsCode(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();

        String cacheKey = ServiceConfig.CHANGE_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        //发送短信
        return smsFeignService.sendChangePasswordSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改登录密码（手机校验码验证）时，检查手机短信验证码是否正确
     * @param userId 用户Id
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkChangePasswordSmsCode(Long userId, SmsCodeVO smsCodeVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改登录密码（邮箱验证）时，发送邮件验证码
     * @param userId 用户Id
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendChangePasswordEmailCode(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PASSWORD_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));


        String title = "瓴犀B2B平台";
        String content = "【B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, userDO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改登录密码（邮箱验证）时，检查邮件验证码是否正确
     *
     * @param userId 用户Id
     * @param smsCodeVO 接口参数
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> checkChangePasswordEmailCode(Long userId, SmsCodeVO smsCodeVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PASSWORD_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改登录密码
     * @param userId 用户Id
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> changePassword(Long userId, UserUpdatePasswordVO userManageVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String newPassword;
        try {
            newPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(userManageVO.getPassword()));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.BUSINESS_ERROR);
        }

        userDO.setPassword(newPassword);
        memberUserRepository.saveAndFlush(userDO);

        //更改会员的密码
        if(userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            memberDO.setPassword(newPassword);
            memberRepository.saveAndFlush(memberDO);
        }

        return Wrapper.success();
    }

    /**
     * 修改邮箱（手机校验码验证）时，发送手机短信验证码
     * @param userId 用户Id
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangeEmailSmsCode(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_EMAIL_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangeEmailSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改邮箱（手机校验码验证）时，检查手机短信验证码是否正确
     *
     * @param userId 用户Id
     * @param smsCodeVO 接口参数
     * @return 验证结果
     */
    @Override
    public Wrapper<Void> checkChangeEmailSmsCode(Long userId, SmsCodeVO smsCodeVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_EMAIL_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改邮箱（邮箱验证）时，发送邮件验证码
     * @param userId 用户Id
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendChangeEmailEmailCode(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));

        String title = "瓴犀B2B平台";
        String content = "【瓴犀B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, userDO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改邮箱（邮箱验证）时，检查邮件验证码是否正确
     *
     * @param userId 用户Id
     * @param smsCodeVO 接口参数
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> checkChangeEmailEmailCode(Long userId, SmsCodeVO smsCodeVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改邮箱时，向新邮箱发送邮件验证码
     *
     * @param userId 用户Id
     * @param emailVO 接口参数
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendChangeEmailEmailCodeToNew(Long userId, EmailVO emailVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            list.add(criteriaBuilder.equal(root.get("email").as(String.class), emailVO.getEmail().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if(memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));

        String title = "瓴犀B2B平台";
        String content = "【瓴犀B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, emailVO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改邮箱
     * @param userId 用户Id
     * @param loginSource 登录来源
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> changeEmail(Long userId, Integer loginSource,  UserUpdateEmailVO userManageVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!userManageVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if(loginSource.equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            } else {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            }

            list.add(criteriaBuilder.equal(root.get("email").as(String.class), userManageVO.getEmail().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if(memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        userDO.setEmail(userManageVO.getEmail());
        memberUserRepository.saveAndFlush(userDO);

        //更改会员的邮箱
        if(userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            memberDO.setEmail(userManageVO.getEmail());
            memberRepository.saveAndFlush(memberDO);
        }

        //删除缓存
        memberCacheService.deleteString(cacheKey);

        return Wrapper.success();
    }

    /**
     * 修改手机号码（手机校验码验证）时，发送手机短信验证码
     * @param userId 用户Id
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePhoneSmsCode(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangePhoneSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改手机号码（手机校验码验证）时，检查手机短信验证码是否正确
     *
     * @param userId 用户Id
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkChangePhoneSmsCode(Long userId, SmsCodeVO smsCodeVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改手机号码（邮箱验证）时，发送邮件验证码
     * @param userId 用户Id
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePhoneEmailCode(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PHONE_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));

        String title = "瓴犀B2B平台";
        String content = "【瓴犀B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, userDO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改手机号码（邮箱验证）时，检查邮件验证码是否正确
     *
     * @param userId 用户Id
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkChangePhoneEmailCode(Long userId, SmsCodeVO smsCodeVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PHONE_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改手机号码时，向新手机号码发送短信验证码
     *
     * @param userId 用户Id
     * @param loginSource 登录来源
     * @param phoneVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePhoneSmsCodeToNew(Long userId, Integer loginSource, PhoneVO phoneVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if(loginSource.equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            } else {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            }

            list.add(criteriaBuilder.equal(root.get("phone").as(String.class), phoneVO.getPhone().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if(memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangePhoneSms(phoneVO.getCountryCode(), phoneVO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改手机号
     * @param userId 用户Id
     * @param loginSource 登录来源
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> changePhone(Long userId, Integer loginSource, UserUpdatePhoneVO userManageVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!userManageVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        //查询手机号码是否已经存在
        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if(loginSource.equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            } else {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            }

            list.add(criteriaBuilder.equal(root.get("phone").as(String.class), userManageVO.getPhone().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if(memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        userDO.setPhone(userManageVO.getPhone());
        //如果是会员的管理员用户：
        //账号就是手机号，所以要更新两个字段
        //会员的账号也是手机号
        if(userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            userDO.setAccount(userManageVO.getPhone());

            memberDO.setAccount(userManageVO.getPhone());
            memberDO.setPhone(userManageVO.getPhone());
            memberRepository.saveAndFlush(memberDO);
        }

        memberUserRepository.saveAndFlush(userDO);

        //删除缓存
        memberCacheService.deleteString(cacheKey);

        return Wrapper.success();
    }

    /**
     * 重置支付密码时，发送手机短信验证码
     * @param userId 用户Id
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePayPswSmsCode(Long userId) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PAY_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangePayPasswordSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 重置支付密码时，检查手机短信验证码是否正确
     * @param userId 用户Id
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkChangePayPswSmsCode(Long userId, SmsCodeVO smsCodeVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PAY_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if(!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if(!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 手机校验码验证后，修改支付密码
     * @param userId 用户Id
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> changePayPassword(Long userId, UserUpdatePayPasswordVO userManageVO) {
        MemberUserDO userDO = memberUserRepository.findById(userId).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if(memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String encryptPayPassword;
        try {
            encryptPayPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(userManageVO.getPayPassword()));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.SERVICE_ERROR);
        }

        memberDO.setPayPassword(encryptPayPassword);
        memberRepository.saveAndFlush(memberDO);

        return Wrapper.success();
    }
}
